reglogin + interceptor

登陆注册

  • 核心思路就是你登陆注册,我判断是否合法,然后创建Ticket,下发Ticket;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    @Controller
    public class LoginController {
    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
    @Autowired
    UserService userService;
    /**
    * regLogin 注册和登陆的处理;默认会跳转到登录页面
    * 该页面可以登陆也可以注册
    *
    * @param model 通过model传递到view,view再通过input传递next值
    * @param next 指之前浏览的页面,登陆注册完就可以跳转过去
    * @return
    */
    @RequestMapping(path = {"/reglogin"}, method = {RequestMethod.GET})
    public String regLogin(Model model,
    @RequestParam(value = "next", defaultValue = "") String next) {
    model.addAttribute("next", next);
    return "login";
    }
    /**
    * reg register的简写;
    * 主要功能就是看看用户能不能进行注册;
    * 通过map得到的ticket跳转响应的页面
    *
    * @param model model
    * @param username 用户名
    * @param password 密码
    * @param next 下一个跳转的页面
    * @param rememberme 是否记住
    * @param response 响应
    * @return
    */
    @RequestMapping(path = {"/reg"}, method = RequestMethod.POST)
    public String reg(Model model,
    @RequestParam("username") String username,
    @RequestParam("password") String password,
    @RequestParam(value = "next", defaultValue = "") String next,
    @RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme,
    HttpServletResponse response) {
    try {
    Map<String, String> map = userService.register(username, password);
    return checkTicket(model, next, rememberme, response, map);
    } catch (Exception e) {
    logger.error("注册异常" + e.getMessage());
    return "login";
    }
    }
    /**
    * 登陆主要就是需要查看用户是不是合法的;
    * 通过userService返回的map,来获取ticket,
    * 然后做出相应跳转
    *
    * @param model
    * @param username
    * @param password
    * @param rememberme 是否记住,决定于是否下发cookie
    * @param next 登录后要跳转的页面
    * @param response 通过响应来下发cookie
    * @return
    */
    @RequestMapping(path = {"/login"}, method = RequestMethod.POST)
    public String login(Model model,
    @RequestParam("username") String username,
    @RequestParam("password") String password,
    @RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme,
    @RequestParam(value = "next", defaultValue = "") String next,
    HttpServletResponse response) {
    try {
    Map<String, String> map = userService.login(username, password);
    return checkTicket(model, next, rememberme, response, map);
    } catch (Exception e) {
    logger.error("注册异常" + e.getMessage());
    return "login";
    }
    }
    /**
    * 将ticket的status置为0,也就是说不能用了,
    * 这样用户就需要重新登陆了,因为本地的cookie值 已经失效;
    * 因为服务器表示你这ticket不能用啊;
    *
    * @param ticket
    * @return
    */
    @RequestMapping(path = {"/logout"}, method = RequestMethod.GET)
    public String logout(@CookieValue("ticket") String ticket) {
    userService.logout(ticket);
    return "redirect:/";
    }
    /**
    * 检验ticket,通过map得到ticket,如果map没有ticket
    * 说明这注册或者登陆不合法,返回map中的msg给view,显示错误信息;
    * 拿到ticket就下发cookie,默认是session,如果点击记住我,时间就是
    * 5天,然后进行跳转,如果有next就跳转next
    * @param model
    * @param next
    * @param rememberme
    * @param response
    * @param map
    * @return
    */
    private String checkTicket(Model model, @RequestParam(value = "next", defaultValue = "") String next, @RequestParam(value = "rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response, Map<String, String> map) {
    if (map.containsKey("ticket")) {
    Cookie cookie = new Cookie("ticket", map.get("ticket"));
    cookie.setPath("/");
    if (rememberme) {
    cookie.setMaxAge(3600 * 24 * 5);
    }
    response.addCookie(cookie);
    if (StringUtils.isNotBlank(next)) {
    return "redirect:" + next;
    }
    return "redirect:/";
    } else {
    model.addAttribute("msg", map.get("msg"));
    return "login";
    }
    }
    }

Ticket

  • 把Ticket叫做T票也不是没有道理的;简单来说就是服务器会制造门票,然后下发给客户端,如果你丢了(cookie过期T票就没了),就不能访问了;服务器也可以主动的将门票设置为不合法,要求你重新登陆一遍

  • 因此存放在服务器里的ticket有一个过期时间,本地cookie也有一个过期时间;

  • 可以通过UUID来生成ticket;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    /**
    * 判断注册是否合法的函数
    * 如果合法的话,就添加盐,盐+password通过md5算法增加保密性;
    * 将用户加入数据库,添加ticket(服务器),然后下发(客户端)
    * @param username
    * @param password
    * @return
    */
    public Map<String, String> register(String username, String password) {
    Map<String, String> map = new HashMap<>();
    if (StringUtils.isBlank(username)) {
    map.put("msg", "用户名不能为空");
    }
    if (StringUtils.isBlank(password)) {
    map.put("msg", "密码不能为空");
    }
    User user = userDAO.selectByName(username);
    if (user != null) {
    map.put("msg", "该用户已经被注册");
    return map;
    }
    user = new User();
    user.setName(username);
    user.setSalt(UUID.randomUUID().toString().substring(0, 5));
    user.setHeadUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));
    //md5 需要重看
    user.setPassword(WendaUtil.MD5(password + user.getSalt()));
    userDAO.addUser(user);
    String ticket = addLoginTicket(user.getId());
    map.put("ticket", ticket);
    return map;
    }
    /**
    * 验证的登陆是否合法,添加ticket,下发ticket
    * @param username
    * @param password
    * @return
    */
    public Map<String, String> login(String username, String password) {
    Map<String, String> map = new HashMap<>();
    if (StringUtils.isBlank(username)) {
    map.put("msg", "用户名不能为空");
    }
    if (StringUtils.isBlank(password)) {
    map.put("msg", "密码不能为空");
    }
    User user = userDAO.selectByName(username);
    if (user == null) {
    map.put("msg", "用户名不存在");
    return map;
    }
    if (!WendaUtil.MD5(password + user.getSalt()).equals(user.getPassword())) {
    map.put("msg", "用户密码错误");
    return map;
    }
    String ticket = addLoginTicket(user.getId());
    map.put("ticket", ticket);
    return map;
    }
    /**
    * 增加ticket,注意日期
    * @param userId
    * @return
    */
    public String addLoginTicket(int userId) {
    LoginTicket loginTicket = new LoginTicket();
    loginTicket.setUserId(userId);
    Date now = new Date();
    now.setTime(now.getTime() + 3600L * 24 * 1000 * 1000);
    loginTicket.setExpired(now);
    loginTicket.setStatus(0);
    loginTicket.setTicket(UUID.randomUUID().toString().replace("-", ""));
    loginTicketDao.addTicket(loginTicket);
    return loginTicket.getTicket();
    }
    /**
    * 将ticket的status置为1
    *
    * @param ticket
    */
    public void logout(String ticket) {
    loginTicketDao.updateStatus(ticket, 1);
    }

Interceptor

  • 拦截器需要注册

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Component
    public class WendaWebConfiguration extends WebMvcConfigurerAdapter {
    @Autowired
    PassportInterceptor passportInterceptor;
    @Autowired
    LoginRequiredInterceptor loginRequiredInterceptor;
    /**
    * 添加拦截器,拦截器会按照顺序执行
    * @param registry
    */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(passportInterceptor);
    registry.addInterceptor(loginRequiredInterceptor).addPathPatterns("/user/*");
    super.addInterceptors(registry);
    }
    }
  • 拦截器针对request

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    @Component
    public class PassportInterceptor implements HandlerInterceptor {
    @Autowired
    LoginTicketDao loginTicketDao;
    @Autowired
    UserDAO userDAO;
    @Autowired
    HostHolder hostHolder;
    //拦截器是针对request的,有多少次request,就经历多少次拦截器
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String ticket = null;
    if (request.getCookies() != null) {
    for (Cookie cookie : request.getCookies()) {
    if (cookie.getName().equals("ticket")) {
    ticket = cookie.getValue();
    break;
    }
    }
    }
    if (ticket != null) {
    LoginTicket loginTicket = loginTicketDao.selectByTicket(ticket);
    if (loginTicket == null || loginTicket.getExpired().before(new Date()) || loginTicket.getStatus() != 0) {
    return true;
    }
    User user = userDAO.selectById(loginTicket.getUserId());
    hostHolder.setUser(user);
    }
    return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    if (modelAndView != null) {
    modelAndView.addObject("user", hostHolder.getUser());
    }
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    hostHolder.clear();
    }
    }